using System;
using System.Linq;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Diagnostics;

namespace ImmediateWindow
{
    public enum DesignNotation
    {
        CSharp, VisualBasic, JavaScript, CPPCLI
    }
    public class CompilerKnobs
    {
        public CompilerKnobs(DesignNotation lang, int warnlevel, bool warnsAsErrs, string switches, ApplicationType apptype)
        {
            Language = lang;
            WarningLevel = warnlevel;
            WarningsAsErrors = warnsAsErrs;
            Switches = switches;
            AddedSwitches = string.Empty;
            ApplicationType = apptype;
        }
        public DesignNotation Language;
        public int WarningLevel;
        public bool WarningsAsErrors;
        public string Switches;
        public string AddedSwitches;
        public ApplicationType ApplicationType;

        public string GetAllCompilerSwitches()
        {
            string apptype = "/target:" + ApplicationType.ToString() + " ";
            return apptype + Switches + AddedSwitches;
        }
    }

    interface IInputOutputForm
    {
        string[] GetSourceLines();
        object[] GetArguments();
        void WriteOutput(string text);
        void ClearOutput();
        List<string> References { get; set; }
        List<string> AvailableReferences { get; set; }
        CompilerKnobs CompilerOption { get; set; }
        Control[] GetFontControls();
    }

    class ActiveImmediate
    {
        string id;
        public ActiveImmediate(Form form)
        {
            id = DateTime.Now.ToLongTimeString();
            itsForm = form;
        }

        public Form itsForm;

        public override string ToString()
        {
            return id;
        }
    }

    public enum ApplicationType
    {
        exe,
        winexe,
        library,
        module
    }

    class WinFormRunner
    {
        Assembly exe;
        object[] args;
        public WinFormRunner(Assembly unit, object[] args) { exe = unit; this.args = args; }
        public void Invoke()
        {
            exe.EntryPoint.Invoke(null, args);
        }
    }

    class Utility
    {
        public static void AdjustSize(Form form)
        {
            if (form == null) return;
            form.Location = new Point(0, 0);
            MainForm parent = form.MdiParent as MainForm;
            form.Size = new Size(parent.Width - parent.CommonBarPanel.Width - 5, parent.Height - 5);
        }

        public static string NormalizeToFileName(string name)
        {
            string nospaces = name.Replace(' ', '-');
            return "GEN-" + nospaces.Replace(':', '-') + ".EXE";
        }

        /*private static string GetWindowsSdkInstallationFolder()
        {
          //FrameworkSDKDir=C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0
          //SdkTools=C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin

          //program =  FrameworkSDKDir + "\\bin\\ildasm.exe"
          //program =  SdkTools + "\\ildasm.exe"

          string location = Environment.GetEnvironmentVariable("FrameworkSDKDir");
          if (string.IsNullOrEmpty(location))
            location = Environment.GetEnvironmentVariable("SdkTools");
          else
            location = location + "\\bin";
          if (!string.IsNullOrEmpty(location))
            location = location + "\\";
          return location;
        }*/

        private static string GetWindowsSdkInstallationFolder()
        {
            //HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows v6.0A v7.0A InstallationFolder
            using (Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Microsoft SDKs\Windows"))
            {
                if (key == null) throw new Exception("key null");
                string[] vers = key.GetSubKeyNames();
                if (vers.Length <= 0) throw new Exception("No Windows SDK versions found. I need ILDASM.EXE");
                Array.Sort(vers); // LINQ expr desc
                using (var fxver = key.OpenSubKey(vers[vers.Length - 1]))
                {
                    object path = fxver.GetValue("InstallationFolder");
                    if (path == null) throw new Exception("Windows SDK InstallationFolder is null. I need ILDASM.EXE");
                    string InstallationFolder = System.IO.Path.Combine(path.ToString(), "bin");
                    return InstallationFolder;
                }
            }
        }

        public static string Disassemble(string assembly_name)
        {
            string MSIL_lines = null;

            try
            {
                string location = GetWindowsSdkInstallationFolder();
                string ILDasm = Find(location, "ILDASM.EXE");// System.IO.Path.Combine(location, "ILDASM.EXE");
                using (Process ildasm = new Process())
                {
                    ildasm.StartInfo.FileName = ILDasm;
                    ildasm.StartInfo.Arguments = "/text " + assembly_name;
                    ildasm.StartInfo.CreateNoWindow = true;
                    ildasm.StartInfo.UseShellExecute = false;
                    ildasm.StartInfo.RedirectStandardOutput = true;
                    ildasm.Start();
                    MSIL_lines = ildasm.StandardOutput.ReadToEnd();
                    ildasm.WaitForExit();
                }
            }
            catch (Exception err)
            {
                MSIL_lines = err.Message;
            }
            return MSIL_lines;
        }

        private static string Find(string foldername, string file)
        {
            var result = Find(new System.IO.DirectoryInfo(foldername), file);
            if (result == null)
            {
                throw new Exception(string.Format("{0} not found in path hierarchy root {1}", file, foldername));
            }
            return result;
        }
        private static string Find(System.IO.DirectoryInfo folder, string file)
        {
            var target = folder.GetFiles(file).FirstOrDefault(f => string.Compare(f.Name, file, true) == 0);
            if (target != null)
            {
                return target.FullName;
            }
            else
            {
                string result = null;
                foreach (var subfolder in folder.GetDirectories())
                {
                    result = Find(subfolder, file);
                    if (result != null)
                    {
                        break;
                    }
                }
                return result;
            }
        }
    }
}